/*
    Down In Front: The Android Application
    This application is an interface for Down In Front commentaries.
    Copyright (C) 2011
    Holden Hill <holdenhill@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package down.in.front;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import android.widget.RemoteViews;

/**
 * This is a service that downloads the MP3 versions of Down In Front
 * commentaries to the SD Card. These files are contained in the DownInFront
 * folder, directly accessible from the main directory of the card. This service
 * also creates a notification to show download progress.
 * 
 * @author Holden Hill <holdenhill@gmail.com>
 * 
 */
public class DownloadService extends Service {
	// Create a new action to reference this service.
	static final String DOWNLOAD_ACTION = "down.in.front.download";

	// This service's ID for notifications.
	private static final int DIF_ID = 1;

	// Creates a path to the SD Card.
	private final File ROOT = Environment.getExternalStorageDirectory();

	// Now we're just creating basic objects.
	private final Handler handler = new Handler();
	private Intent intent, updateButton;
	private NotificationManager nManager;
	private PendingIntent pendingIntent;

	// Including wake lock stuff.
	private PowerManager pmanager;
	private PowerManager.WakeLock wake;

	// ...and these random variables.
	private long fileDownloaded, totalSize, progress = 1;

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		updateButton = new Intent(DOWNLOAD_ACTION);
	}

	@Override
	public void onStart(final Intent intent, int startid) {
		try {
			Intent notificationIntent = new Intent(this, ReleaseView.class);
			this.intent = intent;

			// Create a pending intent to reference the original activity from
			// the notification.
			pendingIntent = PendingIntent.getActivity(getApplicationContext(),
					0, notificationIntent, 0);

			String ns = Context.NOTIFICATION_SERVICE;

			// Create the information to go inside the notification.
			CharSequence title = "Down In Front";
			CharSequence text = "Downloading "
					+ intent.getExtras().getString("title") + "...";
			long when = System.currentTimeMillis();

			// Create the notification using a custom layout.
			Notification notification = new Notification(R.drawable.icon,
					title, when);
			notification.flags = notification.flags
					| Notification.FLAG_ONGOING_EVENT
					| Intent.FLAG_ACTIVITY_CLEAR_TOP
					| Intent.FLAG_ACTIVITY_SINGLE_TOP;

			// Plug the information into the notification.
			notification.contentIntent = pendingIntent;
			notification.contentView = new RemoteViews(getApplicationContext()
					.getPackageName(), R.layout.notification);
			notification.contentView.setImageViewResource(R.id.icon,
					R.drawable.icon);
			notification.contentView.setProgressBar(R.id.progressNotifyBar,
					100, (int) progress, false);
			notification.contentView.setTextViewText(R.id.text, text);
			notification.contentView.setTextViewText(R.id.percent, "0%");
			Log.i("DOWN IN FRONT : NOTIFICATION", "Working so far.");

			// Create a manager to handle the notification.
			nManager = (NotificationManager) getApplicationContext()
					.getSystemService(ns);
			nManager.notify(DIF_ID, notification);

			// Establish a wake lock to prevent the download from dying.
			pmanager = (PowerManager) getSystemService(Context.POWER_SERVICE);
			wake = pmanager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
					"Download Lock");
			Log.i("DOWN IN FRONT : WAKELOCK",
					"Set up Wake Lock for file download.");

			// Start up a new thread to download the file in.
			Thread download = new Thread() {
				@Override
				public void run() {
					int id = intent.getExtras().getInt("id", 0);
					Log.i("DOWN IN FRONT : DOWNLOADING", "ID: " + id);
					String link = intent.getExtras().getString("playerLink");
					Log.i("DOWN IN FRONT : DOWNLOADING", "URL: " + link);

					try {
						URL url = new URL(link);
						String filename = "/DownInFront/audio-" + id + ".mp3";

						// Create the DownInFront folder if it doesn't exist.
						File difFolder = new File(ROOT + "/DownInFront/");
						if (!difFolder.exists())
							difFolder.mkdirs();

						// Start the file download.
						File file = new File(ROOT, filename);
						file.createNewFile();

						Log.i("DOWN IN FRONT : MP3 SERVICE",
								"download begining");
						Log.i("DOWN IN FRONT : MP3 SERVICE", "download url:"
								+ url);
						Log.i("DOWN IN FRONT : MP3 SERVICE",
								"downloaded file name:" + "audio-" + id
										+ ".mp3");

						// Start up the wake lock.
						wake.acquire();

						// Open a connection to the MP3 file.
						URLConnection ucon = url.openConnection();
						ucon.connect();
						InputStream is = ucon.getInputStream();
						FileOutputStream fos = new FileOutputStream(file);
						byte[] buffer = new byte[1024];
						int length = 0;
						fileDownloaded = 0;
						totalSize = ucon.getContentLength();
						handler.postDelayed(update, 0);

						// Store the file on the SD card.
						while ((length = is.read(buffer)) > 0) {
							fos.write(buffer, 0, length);
							fileDownloaded += length;
						}

						// ...then kill the connection with fire.
						fos.close();
						wake.release();
						Log.i("DOWN IN FRONT : MP3 SERVICE",
								"MP3 Downloaded. GG.");
						updateButton.putExtra("finished", true);
						sendBroadcast(updateButton);
						stopSelf();
					} catch (IOException e) {
						Log.d("DOWN IN FRONT : MP3 SERVICE", "Error: " + e);
						e.printStackTrace();
					}
				}
			};

			download.start();
		} catch (Exception e) {
			Log.i("WHOA", "No sale.");
			e.printStackTrace();
		}
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		nManager.cancel(DIF_ID);
		handler.removeCallbacks(update);
	}

	private Runnable update = new Runnable() {
		@Override
		public void run() {
			// Update the progress bar.
			float percent = (float) fileDownloaded / (float) totalSize;
			progress = (int) (100 * percent);

			// We had to do all of this already, but notifications create a
			// memory leak if they are reused, so we have to recreate it on each
			// update. It's kind of lame, but there's no better way around it.
			// You've seen all of this before.
			CharSequence title = "Down In Front";
			CharSequence text = "Downloading "
					+ intent.getExtras().getString("title") + "...";
			long when = System.currentTimeMillis();

			Notification notification = new Notification(R.drawable.icon,
					title, when);
			notification.flags = notification.flags
					| Notification.FLAG_ONGOING_EVENT
					| Intent.FLAG_ACTIVITY_CLEAR_TOP
					| Intent.FLAG_ACTIVITY_SINGLE_TOP;

			notification.contentIntent = pendingIntent;
			notification.contentView = new RemoteViews(getApplicationContext()
					.getPackageName(), R.layout.notification);
			notification.contentView.setImageViewResource(R.id.icon,
					R.drawable.icon);
			notification.contentView.setProgressBar(R.id.progressNotifyBar,
					100, (int) progress, false);
			notification.contentView.setTextViewText(R.id.text, text);
			notification.contentView.setTextViewText(R.id.percent, progress
					+ "%");
			notification.contentView.setProgressBar(R.id.progressNotifyBar,
					100, (int) progress, false);

			Log.i("DOWN IN FRONT : MP3 SERVICE", "downloadedSize:"
					+ fileDownloaded + ", totalSize:" + totalSize
					+ ", percent: " + percent + " = %" + progress);

			nManager.notify(DIF_ID, notification);
			handler.postDelayed(update, 1000);
		}
	};
}
